<template>
  <div class="code-only-view">
    <div class="code-editor">
      <!-- 动态渲染 Monaco 组件（如果加载成功且未切换到 textarea） -->
      <component
        :is="monacoComponent"
        v-if="!useTextarea && monacoComponent"
        :value="code"
        :language="language"
        :theme="theme"
        :options="editorOptions"
        @mount="handleEditorMount"
        @change="handleCodeChange"
      >
        <slot>loading...</slot>
        <slot name="failure">load failure</slot>
      </component>
      <!-- 备用 textarea（当 Monaco 加载失败或强制使用 textarea 时） -->
      <div v-else class="h-full">
        <textarea
          ref="textareaRef"
          :value="code"
          :readonly="readOnly"
          class="html-editor"
          placeholder="HTML 代码..."
          @input="handleTextareaInput"
        />
      </div>
    </div>
    <div class="code-toolbar">
      <ElTooltip
        v-if="!useTextarea"
        content="格式化"
        :show-arrow="false"
        :offset="8"
        transition="slide-fade"
        placement="top"
      >
        <ElButton circle @click="formatCode">
          <Sparkles :size="16" />
        </ElButton>
      </ElTooltip>
      <ElTooltip v-if="false" content="保存" :show-arrow="false" :offset="8" transition="slide-fade" placement="top">
        <ElButton circle @click="handleSaveChange">
          <Save :size="16" />
        </ElButton>
      </ElTooltip>
    </div>
  </div>
</template>

<script setup lang="ts">
import { Save, Sparkles } from "lucide-vue-next"
import { MONACO_OPTIONS } from "@/config/monaco-editor/config"
import type { editor } from "monaco-editor"

interface Props {
  code: string
  language?: string
  theme?: string
  readOnly?: boolean
  debounce?: number
}

interface Emits {
  (e: "change", code: string): void
}

const props = withDefaults(defineProps<Props>(), {
  language: "html",
  theme: "vs-dark", // hc-black hc-light vs-dark
  readOnly: false,
  debounce: 300,
})

const emit = defineEmits<Emits>()

const useTextarea = ref(false)
const monacoComponent = shallowRef<Component | null>(null)
const editorRef = shallowRef<editor.IStandaloneCodeEditor>()
const textareaRef = ref<HTMLTextAreaElement | null>(null)

let debounceTimer: ReturnType<typeof setTimeout> | null = null

/**
 * 编辑器配置
 */
const editorOptions = computed<editor.IStandaloneEditorConstructionOptions>(() => ({
  ...MONACO_OPTIONS,
  readOnly: props.readOnly,
  language: props.language,
}))

const handleEditorMount = (editorInstance: editor.IStandaloneCodeEditor) => {
  editorRef.value = editorInstance
  // setupCustomContextMenu(editor)
  try {
    editorInstance.focus()
  } catch (e) {
    console.warn("focus editor failed:", e)
  }
}

const handleSaveChange = () => {}

const loadMonacoEditor = async () => {
  try {
    const module = await import("@guolao/vue-monaco-editor")
    if (module && typeof module.loader === "object" && typeof module.loader.config === "function") {
      module.loader.config({
        paths: {
          vs: "https://cdn.bootcdn.net/ajax/libs/monaco-editor/0.53.0/min/vs",
        },
      })
    }

    monacoComponent.value = module.VueMonacoEditor ?? module.default ?? null
    if (!monacoComponent.value) {
      throw new Error("Monaco component not found in module")
    }
  } catch (error) {
    console.warn("Monaco Editor 加载失败，切换到备用编辑器:", error)
    useTextarea.value = true
    monacoComponent.value = null
  }
}

const emitChangeDebounced = (value: string) => {
  if (debounceTimer) {
    clearTimeout(debounceTimer)
  }

  debounceTimer = setTimeout(() => {
    emit("change", value)
    debounceTimer = null
  }, props.debounce)
}

const handleTextareaInput = (event: Event) => {
  const target = event.target as HTMLTextAreaElement
  emitChangeDebounced(target.value)
}

const handleCodeChange = (value: string | undefined) => {
  emitChangeDebounced(value ?? "")
}

const formatCode = () => {
  editorRef.value?.getAction("editor.action.formatDocument")?.run()
}

const clearCode = () => {
  const emptyValue = ""

  if (editorRef.value) {
    editorRef.value.setValue(emptyValue)
  }

  emit("change", emptyValue)
}

const getCode = (): string => {
  return editorRef.value?.getValue() || props.code
}

const focusEditor = () => {
  if (editorRef.value) {
    editorRef.value.focus()
  } else if (useTextarea.value) {
    // 如果是 textarea，获取 DOM 元素并聚焦
    nextTick(() => {
      const textarea = document.querySelector(".html-editor") as HTMLTextAreaElement
      textarea?.focus()
    })
  }
}

const getEditor = () => {
  return editorRef.value
}

watch(
  () => props.code,
  (newValue) => {
    if (!editorRef.value) return

    const currentValue = editorRef.value?.getValue()
    if (newValue !== currentValue) {
      const position = editorRef.value.getPosition()
      editorRef.value.setValue(newValue)
      if (position) {
        // 恢复光标位置
        editorRef.value.setPosition(position)
      }
    }
  }
)

onMounted(() => {
  // loadMonacoEditor()
})

onBeforeUnmount(() => {
  if (debounceTimer) {
    clearTimeout(debounceTimer)
  }
})

defineExpose({
  formatCode,
  clearCode,
  getCode,
  focus: focusEditor,
  getEditor,
})
</script>

<style lang="scss" scoped>
.code-only-view {
  position: relative;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: #1e1e1e;

  .code-editor {
    flex: 1;
    position: relative;
    overflow: hidden;
  }
  .html-editor {
    width: 100%;
    height: 100%;
    border: none;
    outline: none;
    padding: 16px;
    font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
    font-size: 14px;
    line-height: 1.5;
    background: var(--el-bg-color);
    color: var(--el-text-color-primary);
    resize: none;
    box-sizing: border-box;
  }

  .code-toolbar {
    right: 12px;
    bottom: 10px;
    position: absolute;
  }
}
</style>
